/******************************************************************************
* File:             jx_lcd.c
*
* Author:           iysheng
* Created:          12/03/20
* Description:      DaLian JiaXian SPI Lcd Driver
*****************************************************************************/

#include <rtthread.h>
#include <drv_common.h>
#include <drv_spi.h>
#include <rtdevice.h>

#define DBG_TAG "jxlcd"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>

#include "jx_lcd.h"
#include "kt.h"
#include "redclock_background.h"
#include "jx_num.h"
#include "jx_demo.h"

#define SUPPORT_RED_CLOCK
static red_spi_lcd_t g_jx_lcd_dev;
static jx_lcd_disp_map_t g_jx_fonticons_maps[3];
static int g_jx_fonticons_maps_counts;
enum {
    JX_LCD_TYPE_CMD = 0,
    JX_LCD_TYPE_DATA
};

/* 定義 jx lcd 分辨率 */
#define JX_LCD_LENGTH_PIEX  400
#define JX_LCD_WIDTH_PIEX   300

#define DATA_CMD_PIN        GET_PIN(I, 5)
#define BUSY_PIN            GET_PIN(A, 15)
#define RESET_PIN           GET_PIN(A, 8)

#define JX_LCD_DATA_MODE rt_pin_write(DATA_CMD_PIN, PIN_HIGH)
#define JX_LCD_CMD_MODE  rt_pin_write(DATA_CMD_PIN, PIN_LOW)

#define MAX_ICONS_COUNTS        12
#define MAX_4040ICONS_COUNTS    13

static jx_lcd_disp_t gImage_8080_icons[MAX_ICONS_COUNTS] = {
    {0, gImage_number_0},
    {1, gImage_number_1},
    {2, gImage_number_2},
    {3, gImage_number_3},
    {4, gImage_number_4},
    {5, gImage_number_5},
    {6, gImage_number_6},
    {7, gImage_number_7},
    {8, gImage_number_8},
    {9, gImage_number_9},
    {10, gImage_tomato}, /* 番茄時鍾圖標 */
};

/* 40*40 icons 圖表集合 */
static jx_lcd_disp_t gImage_4040_icons[MAX_4040ICONS_COUNTS] = {
    {0, gImage_s_number_0},
    {1, gImage_s_number_1},
    {2, gImage_s_number_2},
    {3, gImage_s_number_3},
    {4, gImage_s_number_4},
    {5, gImage_s_number_5},
    {6, gImage_s_number_6},
    {7, gImage_s_number_7},
    {8, gImage_s_number_8},
    {9, gImage_s_number_9},
    {10, gImage_sunny},
    {11, gImage_rain},
    {12, gImage_cloudy},
};

static int jx_lcd_icons_init(void)
{
    int i = 0;

    /* 80*80 的像素圖片初始化 */
    g_jx_fonticons_maps[i].map_counts = MAX_ICONS_COUNTS;
    g_jx_fonticons_maps[i].pixel_high = 80;
    g_jx_fonticons_maps[i].pixel_width = 80;
    g_jx_fonticons_maps[i].maps = gImage_8080_icons;
    i++;
    /* 40*40 的像素圖片初始化 */
    g_jx_fonticons_maps[i].map_counts = MAX_4040ICONS_COUNTS;
    g_jx_fonticons_maps[i].pixel_high = 40;
    g_jx_fonticons_maps[i].pixel_width = 40;
    g_jx_fonticons_maps[i].maps = gImage_4040_icons;
    i++;

    return i;
}

/*
 * jx_trans2lcd: 發送數據到 lcd
 *
 * data: 待發送的數據
 * data_type: 數據的類型，1: 表示數據 0: 表示命令
 * */
static rt_err_t jx_trans2lcd(unsigned char data, unsigned char data_type)
{
    if (data_type == JX_LCD_TYPE_DATA)
    {
        JX_LCD_DATA_MODE;
    }
    else if (data_type == JX_LCD_TYPE_CMD)
    {
        JX_LCD_CMD_MODE;
    }

    rt_spi_send(g_jx_lcd_dev.spi_dev_ptr, &data, 1);

    return 0;
}

/*
 * jx_wait4free: 等待屏幕空閒
 *
 * return N/A
 * */
static void jx_wait4free(void)
{
    while(PIN_HIGH == rt_pin_read(BUSY_PIN))
    {
        rt_thread_mdelay(10);
    };
}

int jx_show_picture_small_red(unsigned short start_x, unsigned short start_y, \
    unsigned short length, unsigned short width, \
    const unsigned char *red_data)
{
/* 官方推薦局部刷新次數不要超過 5 次，查過後需要全局刷新一次，否則容易導致有些
 * 區域無法正常顯示，此處爲了測試暫時設置爲 3 次 */
#define PART_REFRESH_MAX_COUNTS    1000
    static unsigned int part_refresh_counts;
    unsigned short i, piex_counts;
    unsigned short end_x, end_y;

    if (part_refresh_counts > PART_REFRESH_MAX_COUNTS)
    {
        LOG_I("part refresh counts=%u > %u just return", part_refresh_counts, \
            PART_REFRESH_MAX_COUNTS);
        return -1;
    }

    if ((start_x > g_jx_lcd_dev.length_piex) \
        || (start_x + length > g_jx_lcd_dev.length_piex) || \
        (start_y > g_jx_lcd_dev.width_piex) || \
        (start_y + width > g_jx_lcd_dev.width_piex))
    {
        LOG_E("display zone too big");
        return -E2BIG;
    }
    else if ((!width) || (!length))
    {
        LOG_E("invalid display param\n");
        return -EINVAL;
    }
    else
    {
        end_x = start_x + length;
        end_y = start_y + width;
        /* 修正 eny 的值 */
        end_y--;
    }

    /* 設置起始和結束的 x 地址  */
    jx_trans2lcd(0x44, JX_LCD_TYPE_CMD);
    jx_trans2lcd(start_x / 8, JX_LCD_TYPE_DATA); // RAM x address start at 0
    jx_trans2lcd(end_x / 8 - 1, JX_LCD_TYPE_DATA); // RAM x address end at 31h(49+1)*8->400
    /* 設置起始和結束的 y 地址 */
    jx_trans2lcd(0x45, JX_LCD_TYPE_CMD);
    jx_trans2lcd(start_y % 0xff, JX_LCD_TYPE_DATA); // RAM y address end at 00h
    jx_trans2lcd(start_y / 0xff, JX_LCD_TYPE_DATA);
    jx_trans2lcd(end_y % 0xff, JX_LCD_TYPE_DATA);   // RAM y address start at 12Bh
    jx_trans2lcd(end_y / 0xff, JX_LCD_TYPE_DATA);

    jx_trans2lcd(0x4e, JX_LCD_TYPE_CMD);
    jx_trans2lcd(start_x / 8, JX_LCD_TYPE_DATA); // RAM x address start at 0
    /* 設置起始和結束的 y 地址 */
    jx_trans2lcd(0x4f, JX_LCD_TYPE_CMD);
    jx_trans2lcd(start_y % 0xff, JX_LCD_TYPE_DATA);   // RAM y address start at 12Bh
    jx_trans2lcd(start_y / 0xff, JX_LCD_TYPE_DATA);

    /* 填充顯存數據 */
    jx_trans2lcd(0x26, JX_LCD_TYPE_CMD);
    for (i = 0; i < length * width / 8; i++) {
        jx_trans2lcd(~(*red_data++), JX_LCD_TYPE_DATA);
    }
    part_refresh_counts++;

    return 0;
}

int jx_show_picture_small(unsigned short start_x, unsigned short start_y, \
    unsigned short length, unsigned short width, \
    const unsigned char *black_data)
{
/* 官方推薦局部刷新次數不要超過 5 次，查過後需要全局刷新一次，否則容易導致有些
 * 區域無法正常顯示，此處爲了測試暫時設置爲 3 次 */
#define PART_REFRESH_MAX_COUNTS    40
    static unsigned int part_refresh_counts;
    unsigned short i, piex_counts;
    unsigned short end_x, end_y;

    if (part_refresh_counts > PART_REFRESH_MAX_COUNTS)
    {
        LOG_I("part refresh counts=%u > %u just return", part_refresh_counts, \
            PART_REFRESH_MAX_COUNTS);
        return -1;
    }

    if ((start_x > g_jx_lcd_dev.length_piex) \
        || (start_x + length > g_jx_lcd_dev.length_piex) || \
        (start_y > g_jx_lcd_dev.width_piex) || \
        (start_y + width > g_jx_lcd_dev.width_piex))
    {
        LOG_E("display zone too big");
        return -E2BIG;
    }
    else if ((!width) || (!length))
    {
        LOG_E("invalid display param\n");
        return -EINVAL;
    }
    else
    {
        end_x = start_x + length;
        end_y = start_y + width;
        /* 修正 eny 的值 */
        end_y--;
    }

    /* 設置起始和結束的 x 地址  */
    jx_trans2lcd(0x44, JX_LCD_TYPE_CMD);
    jx_trans2lcd(start_x / 8, JX_LCD_TYPE_DATA); // RAM x address start at 0
    jx_trans2lcd(end_x / 8 - 1, JX_LCD_TYPE_DATA); // RAM x address end at 31h(49+1)*8->400
    /* 設置起始和結束的 y 地址 */
    jx_trans2lcd(0x45, JX_LCD_TYPE_CMD);
    jx_trans2lcd(start_y % 0xff, JX_LCD_TYPE_DATA); // RAM y address end at 00h
    jx_trans2lcd(start_y / 0xff, JX_LCD_TYPE_DATA);
    jx_trans2lcd(end_y % 0xff, JX_LCD_TYPE_DATA);   // RAM y address start at 12Bh
    jx_trans2lcd(end_y / 0xff, JX_LCD_TYPE_DATA);

    jx_trans2lcd(0x4e, JX_LCD_TYPE_CMD);
    jx_trans2lcd(start_x / 8, JX_LCD_TYPE_DATA); // RAM x address start at 0
    /* 設置起始和結束的 y 地址 */
    jx_trans2lcd(0x4f, JX_LCD_TYPE_CMD);
    jx_trans2lcd(start_y % 0xff, JX_LCD_TYPE_DATA);   // RAM y address start at 12Bh
    jx_trans2lcd(start_y / 0xff, JX_LCD_TYPE_DATA);

    /* 填充顯存數據 */
    jx_trans2lcd(0x24, JX_LCD_TYPE_CMD);
    for (i = 0; i < length * width / 8; i++) {
        jx_trans2lcd(*black_data++, JX_LCD_TYPE_DATA);
    }
#ifdef SUPPORT_RED_CLOCK
/* 如果開啓了支持紅色，那麼需要將紅色清掉，否則會導致紅色一直存在 */
    jx_trans2lcd(0x26, JX_LCD_TYPE_CMD);
    for (i = 0; i < length * width / 8; i++) {
        jx_trans2lcd(0x00, JX_LCD_TYPE_DATA);
    }
#endif
    part_refresh_counts++;

    return 0;
}

static int jx_lcd_icons_display_red(unsigned int x, unsigned int y, \
    unsigned int pixel_high, unsigned int pixel_width, unsigned int index)
{
    int i, j, ret = -1;

    for (i = 0; i < g_jx_fonticons_maps_counts; i++)
    {
        if ((g_jx_fonticons_maps[i].pixel_high == pixel_high) && \
            (g_jx_fonticons_maps[i].pixel_width == pixel_width))
        {
            for (j = 0; j < g_jx_fonticons_maps[i].map_counts; j++)
            {
                if (g_jx_fonticons_maps[i].maps[j].index == index)
                {
                    jx_show_picture_small_red(x, y, pixel_high, pixel_width, \
                        g_jx_fonticons_maps[i].maps[j].data_ptr);
                    ret = 0;
                    goto over;
                }
            }
        }
    }

over:
    return ret;
}

static int jx_lcd_icons_display(unsigned int x, unsigned int y, \
    unsigned int pixel_high, unsigned int pixel_width, unsigned int index)
{
    int i, j, ret = -1;

    for (i = 0; i < g_jx_fonticons_maps_counts; i++)
    {
        if ((g_jx_fonticons_maps[i].pixel_high == pixel_high) && \
            (g_jx_fonticons_maps[i].pixel_width == pixel_width))
        {
            for (j = 0; j < g_jx_fonticons_maps[i].map_counts; j++)
            {
                if (g_jx_fonticons_maps[i].maps[j].index == index)
                {
                    jx_show_picture_small(x, y, pixel_high, pixel_width, \
                        g_jx_fonticons_maps[i].maps[j].data_ptr);
                    ret = 0;
                    goto over;
                }
            }
        }
    }

over:
    return ret;
}

static rt_size_t jx_lcd_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
{
    LOG_I("do jx_lcd_write");
    static int abc;

    if (!g_jx_lcd_dev.spi_dev_ptr)
    {
        LOG_E("invalid lcd device");
    }

    /* test local refresh */
#if 0
	if (abc++ % 2)
	{
        if (!jx_show_picture_small(0, 80, 80, 80, gImage_number_2))
        {
            jx_lcd_part_refresh();
        }
	}
	else
	{
        if (!jx_show_picture_small(0, 80, 80, 80, gImage_number_6))
        {
            jx_lcd_part_refresh();
        }
	}
#endif

    return RT_EOK;
}

/*
 * int update_display_weather
 * 更新顯示天氣信息
 * 
 * @ unsigned char weather_code: 
 * return: errno/linux
 */
int update_display_weather(unsigned char weather_code)
{
    jx_lcd_icons_display(80, 20, 40, 40, weather_code);

    return 0;
}

/*
 * int update_tomato_time
 * 更新番茄時鍾顯示
 * 
 * @ unsigned char mode: 番茄時鍾的模式 [0: 計算時間 1:設置]
 * @ unsigned int mins: 時間
 * return: errno/Linux
 */
int update_tomato_time(unsigned char mode, unsigned int mins)
{
    static unsigned int s_tomato_mins = 25;
    static unsigned char s_tomato_mode;

    switch (mode)
    {
        case 0:
            if (s_tomato_mode)
            {
                if (s_tomato_mins > mins)
                {
                    s_tomato_mins -= mins;
                }
                else
                {
                    s_tomato_mins = 0;
                }
            }
            else
            {
                goto over;
            }
            break;
        case 1:
            s_tomato_mins = mins;
            /* 顯示番茄時鍾的圖標 */
            jx_lcd_icons_display(40, 205, 80, 80, 10);
        break;
        default:
            LOG_E("invalid mode");
            goto over;
    }

    if (!jx_lcd_icons_display(120, 200, 80, 80, s_tomato_mins % 100 / 10) \
        && !jx_lcd_icons_display(200, 200, 80, 80, s_tomato_mins % 10))
    {
        /* TODO should fresh here ? */
        if (1 == mode)
        {
            s_tomato_mode = mode;
            jx_lcd_part_refresh();
        }
    }

    if (s_tomato_mins == 0)
    {
        jx_lcd_icons_display_red(40, 205, 80, 80, 10);
        /* 一個番茄時鍾周期已經完成 */
        s_tomato_mode = 0;
    }

over:
    return s_tomato_mins;
}


/*
 * int update_display_sensor_value
 * 刷新傳感器的值
 * 
 * @ unsigned short kpa:  氣壓值，單位 KPa
 * @ unsigned short temp: 溫度值單位 m 攝氏度
 * return: errno/Linux
 */
int update_display_sensor_value(unsigned short kpa, unsigned short temp)
{
    int ret = 0;

    if ((kpa > 999) || (temp > 999))
    {
        LOG_E("sensor value too big");
        return -E2BIG;
    }

    if (!jx_lcd_icons_display(40, 160, 40, 40, kpa / 100) \
        && !jx_lcd_icons_display(80, 160, 40, 40, kpa % 100 / 10) \
        && !jx_lcd_icons_display(120, 160, 40, 40, kpa % 10))
    {
        /* TODO should update here ? */
        /* ret = jx_lcd_part_refresh(); */
    }

    if (!jx_lcd_icons_display(240, 160, 40, 40, temp / 100) \
        && !jx_lcd_icons_display(280, 160, 40, 40, temp % 100 / 10) \
        && !jx_lcd_icons_display(320, 160, 40, 40, temp % 10))
    {
        /* TODO should update here ? */
        /* ret = jx_lcd_part_refresh(); */
        jx_lcd_icons_display(316, 192, 8, 8, temp % 10);

        const unsigned char black_point[8] = {0x00, 0x00, 0x00, 0x00, \
            0x00, 0x00, 0x00, 0x00};
        /* 繪制溫度的小數點 */
        jx_show_picture_small(316, 192, 8, 8, black_point);
    }

    return ret;
}

/*
 * int update_display_time
 * 更新系統顯示時間
 * 
 * @ unsigned char hour: 
 * @ unsigned char min: 
 * return: errno/Linux
 */
int update_display_time(unsigned char hour, unsigned char min)
{
    int ret = -1;

    if (!jx_lcd_icons_display(0, 80, 80, 80, hour / 10) \
        && !jx_lcd_icons_display(80, 80, 80, 80, hour % 10) \
        && !jx_lcd_icons_display(240, 80, 80, 80, min / 10) \
        && !jx_lcd_icons_display(320, 80, 80, 80, min % 10))
    {
        /* TODO should update here ? */
        /* ret = jx_lcd_part_refresh(); */
        ret = 0;
    }

    return ret;
}


static rt_err_t jx_lcd_control(rt_device_t dev, int cmd, void *args)
{
    int ret = RT_EOK;
    LOG_I("do jx_lcd_control");

    switch(cmd)
    {
        /* 顯示黑白色 */
        case JX_DISPLAY_BW:
            break;
        /* 顯示紅色 */
        case JX_DISPLAY_RED:
            break;
        /* 黑白和紅色都顯示 */
        case JX_DISPLAY:
            break;
        /* 不支持的命令 */
        default:
            LOG_E("invalid cmd=%u\n", cmd);
            ret = -1;
            break;
    }

    return ret;
}

void jx_lcd_refresh(void)
{
    //DISPLAY REFRESH
    jx_trans2lcd(0x22, JX_LCD_TYPE_CMD);
    jx_trans2lcd(0xC7, JX_LCD_TYPE_DATA);
    /* 更新顯示的時候， busy 管腳一直在高電平 */
    jx_trans2lcd(0x20, JX_LCD_TYPE_CMD);
    jx_wait4free();
}

void jx_lcd_part_refresh(void)
{
    //DISPLAY REFRESH
    jx_trans2lcd(0x22, JX_LCD_TYPE_CMD);
    jx_trans2lcd(0xCF, JX_LCD_TYPE_DATA);
    /* 更新顯示的時候， busy 管腳一直在高電平 */
    jx_trans2lcd(0x20, JX_LCD_TYPE_CMD);
    jx_wait4free();
}

/*
 * void fresh_elink_lcd
 * 刷新墨水屏
 * 
 * @ void: 
 * return: N/A
 */
void fresh_elink_lcd(void)
{
    jx_lcd_refresh();
}

#ifdef RT_USING_DEVICE_OPS
const static struct rt_device_ops lcd_dev_ops =
{
    RT_NULL,
    RT_NULL,
    RT_NULL,
    jx_lcd_read,
    jx_lcd_write,
    jx_lcd_control
};
#endif


/*
 * jx_show_picture: 將傳入的黑白色和紅色的顏色數據寫到屏幕
 *
 * black_data：黑白色的數據
 * red_data：紅色的數據
 *
 * return N/A
 * */
void jx_show_picture(const unsigned char *black_data, const unsigned char *red_data)
{
    unsigned int i;

    /* 填充黑白色的顏色數據 */
    jx_trans2lcd(0x24, JX_LCD_TYPE_CMD);
    if (black_data)
    {
        for (i = 0; i < 15000; i++) {
            jx_trans2lcd(~(*black_data), JX_LCD_TYPE_DATA);
            black_data++;
        }
    }
    else
    {
        /* 默認填充白色 */
        for (i = 0; i < 15000; i++) {
            jx_trans2lcd(0xff, JX_LCD_TYPE_DATA);
            red_data++;
        }
    }

#ifdef SUPPORT_RED_CLOCK
    /* 填充紅色的顏色數據 */
    jx_trans2lcd(0x26, JX_LCD_TYPE_CMD);
    if (red_data)
    {
        for (i = 0; i < 15000; i++) {
            jx_trans2lcd(~(*red_data), JX_LCD_TYPE_DATA);
            red_data++;
        }
    }
    else
    {
        /* 默認不渲染紅色 */
        for (i = 0; i < 15000; i++) {
            jx_trans2lcd(0x00, JX_LCD_TYPE_DATA);
            red_data++;
        }
    }
#endif
}

static int jx_lcd_init(void)
{
    int ret;

    struct rt_spi_configuration cfg = {0};
    __HAL_RCC_GPIOI_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    rt_pin_mode(DATA_CMD_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(RESET_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(BUSY_PIN, PIN_MODE_INPUT);
    /* 片選管腳是 PI0 */
    rt_hw_spi_device_attach("spi2", "spi20", GPIOI, GPIO_PIN_0);

    g_jx_lcd_dev.spi_dev_ptr = (struct rt_spi_device *)rt_device_find("spi20");

    if (!g_jx_lcd_dev.spi_dev_ptr)
    {
        LOG_E("no found such spi device");
        return -EINVAL;
    }
    else
    {
        /* 設置顯示器的分辨率 */
        g_jx_lcd_dev.length_piex = JX_LCD_LENGTH_PIEX;
        g_jx_lcd_dev.width_piex = JX_LCD_WIDTH_PIEX;
    }
    cfg.data_width = 8;
    cfg.mode = RT_SPI_MASTER | RT_SPI_MODE_0 | RT_SPI_MSB;
    cfg.max_hz = 20 * 1000 *1000;                           /* 20M */

    rt_spi_configure(g_jx_lcd_dev.spi_dev_ptr, &cfg);

    /* 初始化顯示屏驅動 */
    /* 軟件復位， 拉低爲 0 ，等待 1s 拉高，等待 1s */
    rt_pin_write(RESET_PIN, PIN_LOW);
    rt_thread_delay(RT_TICK_PER_SECOND);
    rt_pin_write(RESET_PIN, PIN_HIGH);
    rt_thread_delay(RT_TICK_PER_SECOND);

    /* 發送 0x12 命令復位 */
    jx_trans2lcd(0x12, JX_LCD_TYPE_CMD);

    /* 等待 busy 管腳爲 0 */
    jx_wait4free();

    jx_trans2lcd(0x74, JX_LCD_TYPE_CMD);
    jx_trans2lcd(0x54, JX_LCD_TYPE_DATA);
    jx_trans2lcd(0x7E, JX_LCD_TYPE_CMD);
    jx_trans2lcd(0x3B, JX_LCD_TYPE_DATA);
    jx_trans2lcd(0x2B, JX_LCD_TYPE_CMD);  // Reduce glitch under ACVCOM
    jx_trans2lcd(0x04, JX_LCD_TYPE_DATA);
    jx_trans2lcd(0x63, JX_LCD_TYPE_DATA);

    jx_trans2lcd(0x0C, JX_LCD_TYPE_CMD);  // Soft start setting
    jx_trans2lcd(0x8B, JX_LCD_TYPE_DATA);
    jx_trans2lcd(0x9C, JX_LCD_TYPE_DATA);
    jx_trans2lcd(0x96, JX_LCD_TYPE_DATA);
    jx_trans2lcd(0x0F, JX_LCD_TYPE_DATA);

    jx_trans2lcd(0x01, JX_LCD_TYPE_CMD);  // Set MUX as 300
    jx_trans2lcd(0x2B, JX_LCD_TYPE_DATA);
    jx_trans2lcd(0x01, JX_LCD_TYPE_DATA);
    jx_trans2lcd(0x00, JX_LCD_TYPE_DATA);

    /* 修改地址增減方向 */
    jx_trans2lcd(0x11, JX_LCD_TYPE_CMD);  // Data entry mode
    jx_trans2lcd(0x03, JX_LCD_TYPE_DATA);
    /* 設置起始和結束的 x 地址  */
    jx_trans2lcd(0x44, JX_LCD_TYPE_CMD);
    jx_trans2lcd(0x00, JX_LCD_TYPE_DATA); // RAM x address start at 0
    jx_trans2lcd(0x31, JX_LCD_TYPE_DATA); // RAM x address end at 31h(49+1)*8->400
    /* 設置起始和結束的 y 地址  */
    jx_trans2lcd(0x45, JX_LCD_TYPE_CMD);
    jx_trans2lcd(0x00, JX_LCD_TYPE_DATA); // RAM y address end at 00h
    jx_trans2lcd(0x00, JX_LCD_TYPE_DATA);
    jx_trans2lcd(0x2B, JX_LCD_TYPE_DATA);   // RAM y address start at 12Bh
    jx_trans2lcd(0x01, JX_LCD_TYPE_DATA);

    jx_trans2lcd(0x3C, JX_LCD_TYPE_CMD); // board
    jx_trans2lcd(0x01, JX_LCD_TYPE_DATA); // HIZ

/* 如果沒有定義支持紅色顯示，那麼 bypass 紅色值 */
/* 旁路掉紅色顯示，僅支持黑白顯示 */
    jx_trans2lcd(0x21, JX_LCD_TYPE_CMD); // board
#ifndef SUPPORT_RED_CLOCK
    jx_trans2lcd(0x40, JX_LCD_TYPE_DATA); // HIZ
#else
    jx_trans2lcd(0x00, JX_LCD_TYPE_DATA); // HIZ
#endif

    jx_trans2lcd(0x18, JX_LCD_TYPE_CMD);
    jx_trans2lcd(0X80, JX_LCD_TYPE_DATA);
    jx_trans2lcd(0x22, JX_LCD_TYPE_CMD);
    jx_trans2lcd(0XB1, JX_LCD_TYPE_DATA);    //Load Temperature and waveform setting.
    /* 激活控制器顯示 */
    jx_trans2lcd(0x20, JX_LCD_TYPE_CMD);
    /* 等待控制器空閒 */
    jx_wait4free();

    jx_trans2lcd(0x4E, JX_LCD_TYPE_CMD);
    jx_trans2lcd(0x00, JX_LCD_TYPE_DATA);
    jx_trans2lcd(0x4F, JX_LCD_TYPE_CMD);
    jx_trans2lcd(0x00, JX_LCD_TYPE_DATA);
    jx_trans2lcd(0x00, JX_LCD_TYPE_DATA);

    g_jx_fonticons_maps_counts = jx_lcd_icons_init();
#if 0
    rt_kprintf("show demo data -------------\n");
    jx_show_picture(g_jx_demo_black_data, g_jx_demo_red_data);
#elif 1
    rt_kprintf("show redclock background n=%d\n", \
        g_jx_fonticons_maps_counts);
    jx_show_picture(gImage_redclock_background, NULL);
#else
    rt_kprintf("show kt data -------------\n");
    jx_show_picture(gImage_kt, NULL);
#endif

    rt_kprintf("will refresh the lcd .....\n");
#if 0
    jx_lcd_refresh();
    rt_thread_mdelay(200);
#endif
    rt_kprintf("refresh the lcd end.....\n");
    /* TODO 注冊 jx_lcd 驅動 */
#ifdef RT_USING_DEVICE_OPS
    g_jx_lcd_dev.lcd_dev.ops  = &lcd_dev_ops;
#else
    g_jx_lcd_dev.lcd_dev.init = RT_NULL;
    g_jx_lcd_dev.lcd_dev.open = RT_NULL;
    g_jx_lcd_dev.lcd_dev.close = RT_NULL;
    g_jx_lcd_dev.lcd_dev.read = RT_NULL;
    g_jx_lcd_dev.lcd_dev.write = jx_lcd_write;
    g_jx_lcd_dev.lcd_dev.control = jx_lcd_control;
#endif
    ret = rt_device_register(&(g_jx_lcd_dev.lcd_dev), JX_LCD_NAME, RT_DEVICE_FLAG_RDWR);
    if (ret != RT_EOK)
    {
        LOG_E("failed reigster jx lcd driver");
    }

    return RT_EOK;
}
/* 顯示屏驅動初始化 */
INIT_ENV_EXPORT(jx_lcd_init);
